package net.lesscoding.parse;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ReUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import net.lesscoding.common.ColumnInfo;
import net.lesscoding.common.CommonConst;
import net.lesscoding.common.TableInfo;
import net.lesscoding.config.RegExrConfig;
import net.lesscoding.config.UserChoose;
import net.lesscoding.utils.ParseUtil;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author eleven
 * @date 2022/7/18 12:17
 * @description
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class MysqlParser extends ParseUtil {

    private UserChoose userChoose;

    /**
     * 解析单条sql
     * @param sql sql语句
     * @return TableInfo 返回解析之后的表数据
     */
    @Override
    public TableInfo parseSql(String sql) {
        sql = sql.toLowerCase().replaceAll("`", "");
        //第一个左括号的下标
        int firstLeftBracket = sql.indexOf(CommonConst.LEFT_BRACKET);
        int lastRightBracket = sql.lastIndexOf(CommonConst.RIGHT_BRACKET);
        TableInfo tableInfo = getTable(sql, firstLeftBracket, lastRightBracket);
        List<ColumnInfo> columnList = getColumnList(sql, firstLeftBracket + 1, lastRightBracket);
        tableInfo.setColumnList(columnList);
        tableInfo.setKeyCol(columnList.get(0));
        //获取表名
        return tableInfo;
    }

    private TableInfo getTable(String sql, int left, int right) {
        // 获取建表语句中的 ( 左边的语句获取表名或者视图名
        String tableNameSubstr = sql.substring(0, left);
        String[] createSplit = tableNameSubstr.split(CommonConst.WHITE_SPACE);
        String tableName = createSplit[createSplit.length - 1];
        String tableComment = tableName;
        //获取最后一个 ) 后边的表相关设置
        String tableCommentSubstr = sql.substring(right);
        // 按照 comment 分割字符串
        String[] settingArr = tableCommentSubstr.split(CommonConst.COMMENT);
        //如果表配置后边有comment字符串的话，分割的长度就会大于1
        if (settingArr.length > 1) {
            // 获取comment后边的字符串
            String afterCommentSetting = settingArr[1].trim();
            // 获取mysql的表注释名称
            tableComment = afterCommentSetting.split(CommonConst.WHITE_SPACE)[1].replace("'", "");
        }
        TableInfo tableInfo = new TableInfo();
        tableInfo.setTableName(tableName);
        tableInfo.setTableComment(tableComment);
        return tableInfo;
    }

    private List<ColumnInfo> getColumnList(String sql, int left, int right) {
        // 获取到sql中所有的字段
        sql = sql.substring(left, right).trim();
        List<String> columnStrList = getAllColumn(sql);
        List<ColumnInfo> columnList = new ArrayList<>();
        List<String> keyColList = columnStrList.stream()
                .filter(item -> ReUtil.isMatch(RegExrConfig.MYSQL_KEY, item))
                .collect(Collectors.toList());
        columnStrList.removeAll(keyColList);
        ColumnInfo columnInfo = null;
        for (String columnStr : columnStrList) {
            columnInfo = new ColumnInfo();
            columnStr = columnStr.trim();
            //匹配外键和主键，如果是外键或者主键则跳过
            if(ReUtil.isMatch(RegExrConfig.MYSQL_KEY,columnStr)){
                continue;
            }
            String[] colSetting = columnStr.split(CommonConst.WHITE_SPACE);
            columnInfo.setColumnName(colSetting[0]);
            String dataType = colSetting[1];
            columnInfo.setDataType(dataType);
            columnInfo.setComment(getComment(columnStr));
            columnInfo.setFieldType(getFieldTypeByDataType(dataType));
            if(ReUtil.isMatch(RegExrConfig.MYSQL_DATE,dataType)){
                columnInfo.setIsDateCol(true);
                columnInfo.setPattern("yyyy-MM-dd HH:mm:ss");
            }
            if(ReUtil.isMatch(RegExrConfig.MYSQL_LOCAL_TIME,dataType)){
                columnInfo.setIsDateCol(true);
                columnInfo.setPattern("HH:mm:ss");
            }
            columnList.add(columnInfo);
        }
        return columnList;
    }

    /**
     * 获取字段注释
     * @param columnStr 字段
     * @return
     */
    @Override
    public String getComment(String columnStr){
        if(columnStr.contains(CommonConst.COMMENT)){
            return columnStr.split(CommonConst.COMMENT)[1].replace("'","");
        }
        return "";
    }

    @Override
    public List<TableInfo> parseSql(List<String> sqlList) {
        if (CollUtil.isNotEmpty(sqlList)) {
            List<TableInfo> resultList = new ArrayList<>(sqlList.size());
            for (String sql : sqlList) {
                resultList.add(parseSql(sql));
            }
            return resultList;
        }
        return null;
    }

    @Override
    public List<TableInfo> parseExportSql(String sql) {
        sql = sql.toLowerCase()
                .replace("`", "")
                .replace("\n", "")
                .replace("\r", "")
                .trim();
        List<String> list = Arrays.asList(sql.split(CommonConst.SEMICOLON));
        List<String> createSqlList = list.stream()
                .filter(item -> item.startsWith(CommonConst.CREATE))
                .collect(Collectors.toList());
        return parseSql(createSqlList);
    }

    @Override
    public String getFieldTypeByDataType(String dataType) {
        if(ReUtil.isMatch(RegExrConfig.MYSQL_STRING,dataType)){
            return "String";
        }
        if(ReUtil.isMatch(RegExrConfig.MYSQL_BOOLEAN,dataType)){
            return "Boolean";
        }
        if(ReUtil.isMatch(RegExrConfig.MYSQL_INTEGER,dataType)){
            return "Integer";
        }
        if(ReUtil.isMatch(RegExrConfig.MYSQL_DECIMAL,dataType)){
            return userChoose.getEnableBigDecimal() ? "BigDecimal":"Double";
        }
        if(ReUtil.isMatch(RegExrConfig.MYSQL_LONG,dataType)){
            return "Long";
        }
        if(ReUtil.isMatch(RegExrConfig.MYSQL_DATE,dataType)){
            if (userChoose.getEnableDate()){
                return "Date";
            }
            if (userChoose.getEnableTimestamp()){
                return "Timestamp";
            }
            if (userChoose.getEnableLocalDateTime()){
                return "LocalDateTime";
            }
        }
        if(ReUtil.isMatch(RegExrConfig.MYSQL_LOCAL_TIME,dataType)){
            return "LocalTime";
        }
        return "String";
    }

}
